package com.xjoyt.pay.gateway.aop;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import com.xjoyt.pay.dto.ExecuteResult;
import com.xjoyt.pay.gateway.PayGatewayApp;
import com.xjoyt.pay.gateway.dto.TokenResult;
import com.xjoyt.pay.gateway.params.TokenParam;
import com.xjoyt.pay.gateway.po.TokenLog;
import com.xjoyt.pay.gateway.services.TokenLogService;
import com.xjoyt.pay.master.po.Distributor;
import com.xjoyt.pay.master.po.Merchant;

/**
 * Token截面
 * 
 * @author Administrator
 *
 */
@Component
@Aspect
public class TokenAspect extends AbstractAspect {

    @Around("execution (com.xjoyt.pay.dto.ExecuteResult com.xjoyt.pay.gateway.controllers.MainController.get*AccessToken(..) ) && args(tokenParam) ")
    public ExecuteResult<TokenResult> invoke(ProceedingJoinPoint point,
            TokenParam tokenParam) {
        if (tokenParam == null)
            return ExecuteResult.fail("请输出参数");

        TokenLog entity = new TokenLog();
        entity.success = false;
        entity.token = tokenParam.token;
        entity.sign = tokenParam.sign;
        entity.nonce = tokenParam.nonce;
        entity.timestamp = tokenParam.timestamp;
        try {
            // 调用
            Object[] args = point.getArgs();
            Object val = point.proceed(args);
            @SuppressWarnings("unchecked")
            ExecuteResult<TokenResult> result = (ExecuteResult<TokenResult>) val;
            if (result != null && result.isSuccess()) {
                if (result.getValue() != null) {
                    entity.accessToken = result.getValue().accessToken;
                    setAuth(entity);
                }
                entity.success = true;
            } else {
                entity.errorMessage = result == null ? null
                        : result.getMessage();
            }
            return result;
        } catch (Throwable e) {
            String errerName = "获取token发生异常";
            logger.error(errerName, e);
            e.printStackTrace();
            entity.exception = e.toString();
            return ExecuteResult.fail(errerName);
        } finally {
            save(entity);
        }
    }

    private void setAuth(TokenLog entity) {
        Merchant merchant = getMerchant(entity.accessToken);
        if (merchant != null) {
            entity.merchantId = merchant.id;
            entity.merchantName = merchant.name;
            if (merchant.distributor != null) {
                entity.distributorId = merchant.distributor.id;
                entity.distributorNo = merchant.distributor.no;
                entity.distributorName = merchant.distributor.name;
            }
            if (merchant.distributor.company != null) {
                entity.companyId = merchant.distributor.company.id;
                entity.companyName = merchant.distributor.company.name;
            }
        }

        if (StringUtils.isBlank(entity.distributorId)) {
            Distributor distributor = getDistributor(entity.accessToken);
            if (distributor != null) {
                entity.distributorId = distributor.id;
                entity.distributorNo = distributor.no;
                entity.distributorName = distributor.name;
            }
            if (distributor.company != null) {
                entity.companyId = distributor.company.id;
                entity.companyName = distributor.company.name;
            }
        }
    }

    private void save(TokenLog entity) {
        ExecutorService threadPool = Executors.newCachedThreadPool();
        FutureTask<Object> future = new FutureTask<>(() -> {
            TokenLogService service = PayGatewayApp.applicationContext
                    .getBean(TokenLogService.class);
            service.save(entity);
            return null;
        });
        threadPool.execute(future);
    }
}
